﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using OWLServer.owl.tipos;
using OWLServer.owl.etiquetas;
using OWLServer.owl.interfaces;
using System.Xml.Linq;
using OWLServer.owl.utilidades;
using OWLServer.owl.excepciones;

namespace OWLServer.owl.conversores
{
    /// <summary>
    /// Gestiona las ontologías del sistema.
    /// </summary>
    public class GestorOntologias : IfzGestorOntologias
    {
        #region Miembros de IfzGestosOntologias

        /// <summary>
        /// Obtiene una ontologia de un elemento OWL
        /// </summary>
        /// <param name="ruta">Ruta del archivo de la ontologia</param>
        /// <returns>Ontología recuperada</returns>
        public Ontologia conversorOWLToOntologia(string ruta)
        {
            XElement root = XElement.Load(ruta);
            IList<EspacioNombres> espaciosNombres = UtilidadesEspaciosNombres.getNombresEspacio(root);
            Ontologia ontologia = UtilidadesOntologias.construirOntologia(espaciosNombres, root);
            
            ontologia.Owl = root.ToString();

            construirElementosOntología(root, ontologia);

            return ontologia;
        }

        /// <summary>
        /// Construye los elementos de una contología(clases, propiedades, individuos, etc...)
        /// </summary>
        /// <param name="root">Elemento raiz de OWL</param>
        /// <param name="ontologia">Ontología que estamos construyendo</param>
        private void construirElementosOntología(XElement root, Ontologia ontologia)
        {
            // Obtenemos las clases
            UtilidadesClases.construirClases(ontologia, root);
            // Obtenemos las propiedades
            UtilidadesPropiedades.construirPropiedades(ontologia, root);
            // Obtenemos las claves de las clases
            UtilidadesClases.contruirClavesClase(ontologia, root);
            // Obtenemos las restricciones que puedan existir en la definición de las clases
            UtilidadesRestricciones.construirRestricciones(ontologia, root);
            // Obtenemos los individuos de la ontologia
            UtilidadesIndividuos.construirIndividuos(ontologia, root);
            // Aplicamos las reglas de inferencias derivadas del tipo de propiedades que tienen los individuos.
            UtilidadesInferencias.aplicarInferencias(ontologia);
            // Vemos si existe algun problema al componer el individuo
            UtilidadesProblemas.comprobarProblemas(ontologia);
        }

        /// <summary>
        /// Agrega individuos a una ontologia
        /// </summary>
        /// <param name="ruta">Ruta donde está el OWL con los individuo</param>
        /// <param name="ontologia">Ontología a la que vamos a agregar los individuos</param>
        /// <returns></returns>
        public Ontologia agregarIndividuosOWLToOntologia(string ruta, Ontologia ontologia)
        {
            XElement root = XElement.Load(ruta);

            // Obtenemos los individuos de la ontologia
            UtilidadesIndividuos.construirIndividuos(ontologia, root);
            // Amplicamos las reglas de inferencias derivadas del tipo de propiedades que tienen los individuos.
            UtilidadesInferencias.aplicarInferencias(ontologia);
            // Vemos si existe algun problema al componer el individuo
            UtilidadesProblemas.comprobarProblemas(ontologia);

            return ontologia;
        }

        /// <summary>
        /// Almacena una ontologia en el sistema
        /// </summary>
        /// <param name="ontologia">Ontología a almacena</param>
        /// <param name="reemplazar">En el caso de existir una ya, nos dice si la reemplazamos o no</param>
        public void almacenarOntologia(Ontologia ontologia, bool reemplazar)
        {
            Ontologia onlologiaExistente = UtilidadesOntologias.existeOntologia(ontologia);
            if (!reemplazar && onlologiaExistente != null)
            {
                throw new OntologiaRepetidaException();
            }
            else
            {
                if (reemplazar)
                {
                    if (onlologiaExistente != null)
                    {
                        UtilidadesOntologias.eliminarOntologia(onlologiaExistente);
                    }
                }

                UtilidadesOntologias.almacenarOntologia(ontologia);
            }
        }

        /// <summary>
        /// Actualiza una ontologia en el sistema
        /// </summary>
        /// <param name="ontologia">Ontología a actualizar</param>
        public void actualizarOntologia(Ontologia ontologia)
        {
            UtilidadesOntologias.actualizarOntologia(ontologia);
        }

        /// <summary>
        /// Elimina todas la ontologias del sistema
        /// </summary>
        public void limpiarOntologiasSistema()
        {
            UtilidadesOntologias.limpiarOntologias();
        }

        /// <summary>
        /// Devuelve el listado de ontologias
        /// </summary>
        /// <param name="completa">Sin traelos objetos completados.</param>
        /// <returns></returns>
        public IList<Ontologia> listadoOntologias(bool completa)
        {
            return UtilidadesOntologias.listaOntologias(completa);
        }

        /// <summary>
        /// Recupera una ontologia completa de la base de datos
        /// </summary>
        /// <param name="ontologia">Ontología a recuperar</param>
        /// <returns>Si existe nos la devuelve</returns>
        public Ontologia recuperarOntologiaCompleta(Ontologia ontologia)
        {
            return UtilidadesOntologias.recuperarOntologiaCompleta(ontologia);
        }

        /// <summary>
        /// Nos dice si existe la ontología en el sistema o no
        /// </summary>
        /// <param name="ruta">Ruta del OWL que representa la ontologia</param>
        /// <returns>Si existe o no existe</returns>
        public bool existeOntologia(string ruta)
        {
            XElement root = XElement.Load(ruta);

            IList<EspacioNombres> espaciosNombres = UtilidadesEspaciosNombres.getNombresEspacio(root);
            Ontologia ontologia = UtilidadesOntologias.construirOntologia(espaciosNombres, root);
            bool existe = null != UtilidadesOntologias.existeOntologia(ontologia);

            return existe;
        }

        /// <summary>
        /// Obtiene una ontología a partir de si Identificador
        /// </summary>
        /// <param name="espacioNombrePrincipal">Identificador de espacio Nombre Principal de la ontología</param>
        /// <param name="completa">Indica si se recuperán todos los datos de la ontología de la base de datos.</param>
        /// <returns>Ontología recuperada</returns>
        public Ontologia getOntologiaEspacioNombrePrincipal(string espacioNombrePrincipal, bool completa)
        {
            return UtilidadesOntologias.getOntologiaEspacioNombrePrincipal(espacioNombrePrincipal, true);
        }

        #endregion
    }
}
